package morenoapp.components.thinkgraphv2;

import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PDragSequenceEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PText;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import morenoapp.MorenoApp;
import morenoapp.components.thinkgraph.node.RespondentNode;
import morenoapp.components.thinkgraph.node.VectorNode;
import morenoapp.components.thinkgraph.node.WithTooltip;
import morenoapp.components.thinkgraphv2.nodes.RespondentItemNode;
import morenoapp.components.thinkgraphv2.nodes.VectorItemNode;
import morenoapp.model.listeners.MorenoModelAdapter;
import morenoapp.model.view2.MorenoView2Face;

/**
 *
 * @author root
 */
public class ThinkgraphUICanvas extends ThinkgraphBaseCanvas {
    /**
     * Узел для отображения тултипов.
     */
    PText tooltipNode;
    /**
     * Флаг указывает что при следующем визуальном показе компонента
     * его следует заполить данными из модели.
     */
    boolean needToUpdate = true;

    public ThinkgraphUICanvas(MorenoView2Face _config) {
        super(_config);
        //tooltip
        tooltipNode = new PText();
        tooltipNode.setPickable(false);
        getCamera().addChild(tooltipNode);

        //listeners
        configureListeners();
    }

    public void saveAsImage(File targetFile) throws IOException {
        Dimension componentSize = this.getSize();
        BufferedImage img = new BufferedImage(componentSize.width,
                componentSize.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = img.createGraphics();
        graphics.fillRect(0, 0, img.getWidth(), img.getHeight());
        this.paint(graphics);
        ImageIO.write(img, "png", targetFile); //NOI18N
    }

    /**
     * Добавляет всех необходимых слушателей.
     */
    protected void configureListeners() {
        //Слушатель модели для отслеживания изменений в ней.
        MorenoApp.getModel().addModelListener(new MorenoModelAdapter() {
            @Override
            public void onAnyElementChanged() {
                updateCanvasFromModel();
            }

        });

        config.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.printf(">> %s %s !> %s\n",
                        evt.getPropertyName(),
                        evt.getOldValue(),
                        evt.getNewValue());
                sociogram.propertyChange(evt);
                updateRespondentItemNodes(evt);
                updateVectorItemNodes(evt);
            }

        });
        graph.addInputEventListener(new TooltipNodeDragHandler());
    }

    protected void updateVectorItemNodes(PropertyChangeEvent evt) {
        for (VectorItemNode vector : vectorNodes) {
            vector.propertyChange(evt);
        }
    }

    protected void updateRespondentItemNodes(PropertyChangeEvent evt) {
        for (RespondentItemNode resp : respondentNodes) {
            resp.propertyChange(evt);
        }
    }
    @Override
    public void updateCanvasFromModel() {
        if (isShowing() == true) {
            needToUpdate = false;
            super.updateCanvasFromModel();
        } else {
            needToUpdate = true;
        }
    }

    @Override
    public void paint(Graphics g) {
        if (needToUpdate) {
            updateCanvasFromModel();
        }
        //super.paintComponent(g);
        super.paint(g);
    }

    /**
     * Node handler to display tooltip messages.
     */
    class TooltipNodeDragHandler extends PDragSequenceEventHandler {
        public TooltipNodeDragHandler() {
            getEventFilter().setMarksAcceptedEventsAsHandled(true);
        }

        @Override
        public void mouseEntered(PInputEvent _event) {
            PNode node = _event.getPickedNode();
            if (!_event.isLeftMouseButton()) {
                if (checkNodeType(node, RespondentNode.class)) {
                    node.setPaint(new Color(0xffff88));
                } else if (checkNodeType(node, VectorNode.class)) {
                    setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                }
            }
            updateToolTip(_event);
        }

        @Override
        public void mouseExited(PInputEvent _event) {
            PNode node = _event.getPickedNode();
            if (!_event.isLeftMouseButton()) {
                if (checkNodeType(node, RespondentNode.class)) {
                    node.setPaint(null);
                } else if (checkNodeType(node, VectorNode.class)) {
                    setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
                }
            }
            updateToolTip(null);
        }

        @Override
        public void drag(PInputEvent _event) {
            PNode node = _event.getPickedNode();
            while (node != null) {
                if (node instanceof RespondentItemNode) {
                    node.translate(_event.getDelta().width, _event.getDelta().height);
                    break;
                }
                node = node.getParent();
            }
            updateToolTip(_event);
        }

        private boolean checkNodeType(PNode _node, Class<?> _type) {
            PNode current = _node;
            while (current != null) {
                if (_type.isAssignableFrom(current.getClass())) {
                    return true;
                }
                current = current.getParent();
            }
            return false;
        }

        private void updateToolTip(PInputEvent _event) {
            String tooltipString = null;
            if (_event != null && config.isDisplayTooltips()) {
                PNode node = _event.getInputManager().
                        getMouseOver().
                        getPickedNode();
                while (node != null) {
                    //System.out.println("trace for tooltip: " + node);
                    if (node instanceof WithTooltip) {
                        tooltipString = ((WithTooltip) node).getTooltipText();
                        break;
                    }
                    node = node.getParent();
                }
                //TODO - странный код, не понятно как он работает
                Point2D p = _event.getCanvasPosition();
                p = _event.getPath().
                        canvasToLocal(p, getCamera());
                tooltipNode.setOffset(p.getX() + 12, p.getY() - 23);
            }

            tooltipNode.setText(tooltipString);
        }

    }
}
